#ifndef __TDP2_MAINCONTEXT_HPP__
#define __TDP2_MAINCONTEXT_HPP__


#include "tdp2_husk.hpp"
#include "tdp2_vector.hpp"
#include "tdp2_fpsystem.hpp"
#include "tdp2_respreload.hpp"
#include "tdp2_visualresources.hpp"
#include "tdp2_liveresource.hpp"

#include "../../rdx/src/rdx/rdx_objectmanagement.hpp"
#include "../../rdx/src/rdx/rdx_interpret.hpp"
#include "../../rdx/src/rdx/rdx_plugin.hpp"
#include "../../rdx/src/rdx/rdx_zonepolicy.hpp"

namespace TDP
{
	namespace CoreShaders
	{
		enum CoreShader
		{
			CS_UIGraphic,
			CS_WorldSurfaceGeneric,

			CS_Count,
		};
	}

	class MainContext
	{
	public:
		enum ErrorCode
		{
			ERR_None,
			ERR_InitializeFailed,
		};

	private:
		ErrorCode _lastError;

		ObjectManagement::CRef<TDP::Resources::ShaderInfo::ShaderInfo> _coreShaders[CoreShaders::CS_Count];

		RDX::Programmability::ICodeProvider *_rdxCodeProvider;
		RDX::ObjectManagement::IObjectManager *_objm;
		RDX::ObjectManagement::Allocator _baseAlloc;
		RDX::ObjectManagement::Allocator _alloc;
		RDX::IO::IFileSystem *_mainFS;
		RDX::IO::IFileSystem *_packageFS;
		Rendering::IRenderDevice *_renderDevice;
		
		Containers::Husk<ResourceManagement::ResourcePreloader> _preloader;
		Containers::Husk<ResourceManagement::MFPResourceManager> _mfpRM;
		Containers::Husk<RDX::Security::ZonePolicyPackageHost> _zonePH;
		Containers::Husk<ResourceManagement::MFPFileSystem> _mfpFS;
		Containers::Husk<RDX::CombinedNativeTypeHost> _typeHost;
		Containers::Husk<TDP::Resources::LiveResourceManager> _lrm;
		Containers::Vector<const RDX::ObjectManagement::INativeTypeHost *> _plugins;

		// Active resource being streamed.  Can't be collected until streaming stops.
		ObjectManagement::CRef<TDP::Resources::StreamableResource> _activeStreamingResource;

		// Pending streams
		TDP::Resources::StreamableResource *_firstPendingStream;
		TDP::Resources::StreamableResource *_lastPendingStream;

		static void *WrappedRealloc(void *opaque, void *ptr, LargeInt sz, LargeInt align);
		void DropFirstBundle();

	public:
		MainContext(const TDP::PanicHandler *ph, const RDX::ObjectManagement::INativeTypeHost **plugins,
			const RDX::ObjectManagement::Allocator &allocator, RDX::IO::IFileSystem *fs, Rendering::IRenderDevice *renderDevice);
		~MainContext();
		
		RDX::ObjectManagement::CRef<void> LookupSymbol(RDX::OperationContext *ctx, const RDX::Programmability::String *str);
		RDX::ObjectManagement::IObjectManager *ObjectManager() const;

		void PumpStreaming();
		void AbortStreaming();
		void ReleaseResource(TDP::Resources::LiveResourceHandle rh);
		void ReleaseStreamableResource(TDP::Resources::StreamableResource *sr);
		void RegisterStreamableResource(TDP::Resources::StreamableResource *sr);
		
		Rendering::IRenderDevice *RenderDevice() const;

		static MainContext *FromObjectManager(RDX::ObjectManagement::IObjectManager *objm);
	};
}

#include "../../rdx/src/rdx/rdx_objectmanagement.hpp"

namespace TDP
{
	inline RDX::ObjectManagement::IObjectManager *MainContext::ObjectManager() const
	{
		return _objm;
	}

	inline TDP::MainContext *TDP::MainContext::FromObjectManager(RDX::ObjectManagement::IObjectManager *objm)
	{
		return static_cast<TDP::MainContext*>(objm->GetAllocator()->opaque);
	}
	
	inline TDP::Rendering::IRenderDevice *TDP::MainContext::RenderDevice() const
	{
		return _renderDevice;
	}
}

#endif
